using System;
using System.Collections.Generic;
using System.Text;

namespace Placid.Core
{
    public class PTree : IDisposable
    {
        private Pivot _pv;
        private PTreeNode _horizRoot;
        private PTreeNode _vertRoot;
        private List<PTreeNode> _horizLeafs;
        private List<PTreeNode> _vertLeafs;

        private PTreeNodesMeasuresCollection _nodeMs;

        internal PTree(Pivot pv)
        {
            if (pv != null)
            {
                _pv = pv;
            }
            else throw new Exception("Pv is a null reference.");

            _horizRoot = new PTreeNode("HRoot", null);
            _vertRoot = new PTreeNode("VRoot", null);

            _nodeMs = new PTreeNodesMeasuresCollection();

            _horizLeafs = new List<PTreeNode>();
            _vertLeafs = new List<PTreeNode>();
        }

        public void Build(PSchema schema)
        {
            PTreeNode node;
            PTreeNode lastHNode;
            PTreeNode lastVNode;
            IPivotSourceRow iprow;
            IPivotSourceCell ipcell;
            string nodeName;

            _horizRoot.Clear();
            _vertRoot.Clear();

            if (schema != null && schema.Rows.Count > 0 && schema.Columns.Count > 0)
            {
                for (int rowIndex = 0; rowIndex < _pv.DSrc.RowsCount; rowIndex++)
                {
                    iprow = _pv.DSrc.GetRow(rowIndex);

                    node = _horizRoot;

                    foreach (string colName in schema.Rows)
                    {
                        ipcell = iprow.GetCell(colName);
                        nodeName = colName + "!" + ipcell.ToString();
                        if (node[nodeName] == null)
                        {
                            node.AddNode(new PTreeNode(nodeName));
                        }

                        node = node[nodeName];
                        node.Value = ipcell.Value;
                    }

                    lastHNode = node;
                    if (!_horizLeafs.Contains(lastHNode)) _horizLeafs.Add(lastHNode);

                    node = _vertRoot;

                    foreach (string colName in schema.Columns)
                    {
                        ipcell = iprow.GetCell(colName);
                        nodeName = colName + "!" + ipcell.ToString();
                        if (node[nodeName] == null)
                        {
                            node.AddNode(new PTreeNode(nodeName));
                        }

                        node = node[nodeName];
                        node.Value = ipcell.Value;
                    }

                    lastVNode = node;
                    if (!_vertLeafs.Contains(lastVNode)) _vertLeafs.Add(lastVNode);

                    foreach (string colName in schema.Ms.Keys)
                    {
                        ipcell = iprow.GetCell(colName);
                        _nodeMs.AddNodesMeasure(lastHNode, lastVNode, schema.Ms[colName]).AddMValue(ipcell.Value);
                    }
                }
            }
        }

        public PTreeNode HorizRoot
        {
            get { return _horizRoot; }
        }
        public PTreeNode VertRoot
        {
            get { return _vertRoot; }
        }

        public List<PTreeNode> HorizLeafs
        {
            get { return _horizLeafs; }
        }
        public List<PTreeNode> VertLeafs
        {
            get { return _vertLeafs; }
        }

        public PTreeNodesMeasuresCollection NodeMs
        {
            get { return _nodeMs; }
        }

        #region IDisposable Members

        public void Dispose()
        {
            _horizLeafs.Clear();
            _vertLeafs.Clear();
            _horizRoot.Dispose();
            _vertRoot.Dispose();

            _nodeMs.Dispose();
        }

        #endregion
    }
}
